package com.x.compute.core.context;

import cn.hutool.core.util.StrUtil;
import com.x.compute.core.annotation.ComputeTable;
import com.x.compute.core.annotation.ComputeVar;
import com.x.compute.core.entity.Variable;
import com.x.compute.common.util.ComputeUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 计算变量上下文
 * @author xuxin
 */
@Component
public class VariableContext implements InitializingBean, ApplicationContextAware {

    /**
     * 表格集
     * key：{tableId}
     * value: {tableName}
     */
    public static Map<String, String> tableMap = new ConcurrentHashMap();
    /**
     * 类关联表格id集
     * key：class
     * value: {tableId}
     */
    public static Map<Class, String> classRefTableMap = new ConcurrentHashMap();
    /**
     * 变量集
     */
    public static Map<String, Variable> varMap = new HashMap<>();
    /**
     * 表格中列求和变量集
     * key：{tableId}
     */
    public static Map<String, Set<String>> tableRelColumnSumVarMap = new ConcurrentHashMap();
    /**
     * 列变量集
     */
    public static List<Variable> columnVarList = new ArrayList();
    /**
     * 列变量集
     * key格式：{tableId}_{name}_column
     */
    public static Map<String, Variable> columnVarMap = new ConcurrentHashMap<>();
    /**
     * 表格中列求变量集
     * key：{tableId}
     */
    public static Map<String, Set<String>> tableRelColumnVarMap = new ConcurrentHashMap();
    /**
     * 应用上下文
     */
    private ApplicationContext applicationContext;

    /**
     * 根据类获取tableId
     * @param clazz
     * @return
     */
    public static String getTableId(Class clazz){
        return classRefTableMap.get(clazz);
    }

    /**
     * 获取变量中列变量集合
     * @param varFullNameList 变量集合
     * @return
     */
    public static Map<String, List<Variable>> getColumnVarMap(Set<String> varFullNameList){
        Map<String, List<Variable>> columnMap = new HashMap<>();
        varFullNameList.forEach(varFullName ->{
            Variable variable = columnVarMap.get(varFullName);
            if (variable != null){
                List<Variable> variables = columnMap.getOrDefault(variable.getTableId(), new ArrayList<>());
                variables.add(variable);
                columnMap.put(variable.getTableId(), variables);
            }
        });
        return columnMap;
    }


    @Override
    public void afterPropertiesSet(){
        Collection<Object> classList = applicationContext.getBeansWithAnnotation(ComputeTable.class).values();
        classList.forEach(computeTable ->{
            Class clazz = computeTable.getClass();
            ComputeTable typeAnnotation = (ComputeTable) clazz.getAnnotation(ComputeTable.class);
            String tableId = typeAnnotation.id();
            tableId = StrUtil.isNotBlank(tableId) ? tableId : clazz.getName();
            String tableName = typeAnnotation.name();
            tableMap.put(tableId, tableName);
            classRefTableMap.put(clazz, tableId);
            Field[] fields = clazz.getDeclaredFields();
            boolean notExistSum = true;
            for (Field field : fields) {
                ComputeVar varAnnotation = field.getAnnotation(ComputeVar.class);
                if (varAnnotation == null){
                    continue;
                }
                String varName = varAnnotation.name();
                varName = StrUtil.isNotBlank(varName) ? varName : field.getName();
                String varDesc = varAnnotation.desc();
                Variable rowVar = new Variable(tableId, tableName, varName, varDesc);
                varMap.put(ComputeUtils.getVarFullName(tableId, varName), rowVar);
                if (varAnnotation.sum() && notExistSum){
                    String sumVarName = ComputeUtils.getColumnSumVarName(varName);
                    String sumVarFullName = ComputeUtils.getColumnSumVarFullName(tableId, varName);
                    Variable sumVar = new Variable(tableId, tableName, sumVarName, varDesc);
                    varMap.put(sumVarFullName, sumVar);
                    Set<String> rowSumSet = tableRelColumnSumVarMap.getOrDefault(tableId, new HashSet<>());
                    rowSumSet.add(sumVarFullName);
                    tableRelColumnSumVarMap.put(tableId, rowSumSet);
                }
                if (varAnnotation.column()){
                    Variable columnVar = new Variable(tableId, tableName, varName, varDesc);
                    columnVarList.add(columnVar);
                    columnVarMap.put(ComputeUtils.getColumnVarFullName(tableId, varName), columnVar);
                    Set<String> columnVarSet = tableRelColumnVarMap.getOrDefault(tableId, new HashSet<>());
                    String columnVarFullName = ComputeUtils.getColumnVarFullName(tableId, varName);
                    columnVarSet.add(columnVarFullName);
                    tableRelColumnVarMap.put(tableId, columnVarSet);
                }
            }
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


}
